<template>
  <div class="workflow-view">
    <!-- 操作面板 -->
    <Tabbar :graph="graphObj.graph" class="tabbar-view" @on-save="onSave" />
    <div class="workflow-container">
      <!-- 状态区域 -->
      <a-spin :spinning="graphObj.spinning">
        <div id="stencil" class="stencil-view"></div>
      </a-spin>

      <!-- 画布面板 -->
      <div id="graph-container" class="graph-view"></div>

      <!-- 样式面板 -->
      <RightCircleOutlined v-if="graphObj.isShowPanel" class="panel-icon" @click.stop="setPanel(false)" />
      <LeftCircleOutlined v-else class="panel-icon" @click.stop="setPanel(true)" />
      <Panel v-if="graphObj.isShowPanel" :current-node="graphObj.currentNode" />
    </div>
  </div>
</template>
<script setup lang="ts">
import { Graph, Shape } from "@antv/x6"
import { Stencil } from "@antv/x6-plugin-stencil"
import { Transform } from "@antv/x6-plugin-transform"
import { Selection } from "@antv/x6-plugin-selection"
import { Snapline } from "@antv/x6-plugin-snapline"
import { Clipboard } from "@antv/x6-plugin-clipboard"
import { History } from "@antv/x6-plugin-history"
import { Export } from "@antv/x6-plugin-export"
import Tabbar from "@/components/Business/XTModuleWorkflowEditor/XTModuleWorkflowEditorPanelTabbar.vue"
import Panel from "@/components/Business/XTModuleWorkflowEditor/XTModuleWorkflowEditorPanel.vue"
import { LeftCircleOutlined, RightCircleOutlined } from "@ant-design/icons-vue"

//流程状态数据 & 初始化面板数据
const props = defineProps({
  flowData: {
    type: Array,
    default: () => [],
  },
})
const emits = defineEmits(["onSaveFn"])

// graph 对象需要的数据
const graphObj = reactive({
  graph: {},
  stencil: {
    name: "",
  },
  currentNode: {},
  spinning: true,
  isShowPanel: false,
})

//临时遍历，解决面板则爹问题，存储当前节点数据
let tempCurNode = {}

//监听父组件传递的状态数据和初始化grap数据
watch(
  () => props.flowData,
  (cur, prev) => {
    if (cur) {
      const { graphInitData, statusList } = cur
      //graph 数据回显
      if (graphInitData && Object.keys(graphInitData).length > 0) graphObj.graph.fromJSON(graphInitData)

      //接口获取数据完毕，初始化stencil对象， 并且初始化一次
      if (statusList.length > 0 && !graphObj.stencil.name) initStencil()
    }
  },
  {
    deep: true,
  },
)

onMounted(() => {
  // @1 初始画布
  initGraph()

  //@3 初始化事件
  initEvent()
})
/**
 * 初始画布
 */
const initGraph = (): void => {
  graphObj.graph = new Graph({
    container: document.getElementById("graph-container"),
    autoResize: true,
    grid: true,
    panning: true,
    history: true,
    mousewheel: {
      enabled: true,
      zoomAtMousePosition: true,
      modifiers: "ctrl",
      minScale: 1.5,
      maxScale: 3,
    },
    connecting: {
      router: {
        name: "manhattan",
        args: {
          padding: 1,
        },
      },
      connector: {
        name: "rounded",
        args: {
          radius: 8,
        },
      },
      anchor: "center",
      connectionPoint: "anchor",
      allowBlank: false,
      snap: {
        radius: 20,
      },
      createEdge() {
        //连线的配置
        return new Shape.Edge({
          attrs: {
            line: {
              stroke: "#A2B1C3",
              strokeWidth: 1,
              targetMarker: {
                name: "block",
                width: 12,
                height: 8,
              },
            },
          },
          zIndex: 0,
        })
      },
      validateConnection({ targetMagnet }) {
        return !!targetMagnet
      },
    },
    highlighting: {
      magnetAdsorbed: {
        name: "stroke",
        args: {
          attrs: {
            fill: "#5F95FF",
            stroke: "#5F95FF",
          },
        },
      },
    },
  })

  //插件配置
  graphObj.graph
    .use(
      new Transform({
        resizing: true,
        rotating: true,
      }),
    )
    .use(
      new Selection({
        enabled: true,
        rubberband: true,
        showNodeSelectionBox: true,
      }),
    )
    .use(
      new Snapline({
        enabled: true,
      }),
    )
    .use(
      new Clipboard({
        enabled: true,
      }),
    )
    .use(
      new History({
        enabled: true,
      }),
    )
    .use(
      new History({
        enabled: true,
      }),
    )
    .use(new Export())
}
/**
 * 初始化左侧面板
 */
const initStencil = (): void => {
  graphObj.stencil = new Stencil({
    title: "流程图",
    target: graphObj.graph,
    search: true,
    stencilGraphWidth: 260,
    stencilGraphHeight: 0,
    collapsable: true,
    placeholder: "请输入状态名称",
    notFoundText: "暂未匹配到结果",
    groups: [
      {
        title: "基础流程图",
        name: "baseflow",
        graphWidth: 260,
      },
    ],
    //布局样式调整
    layoutOptions: {
      columns: 2,
      rowHeight: 65,
      resizeToFit: true,
    },
    // search: (cell, keyword, groupName, stencil) => {
    //   if (keyword) return cell.label.includes(keyword)

    //   return true
    // },
  })
  document.getElementById("stencil").appendChild(graphObj.stencil.container)

  // 元素的四个点
  const ports = {
    groups: {
      top: {
        position: "top",
        attrs: {
          circle: {
            r: 4,
            magnet: true,
            stroke: "#5F95FF",
            strokeWidth: 1,
            fill: "#fff",
            style: {
              visibility: "hidden",
            },
          },
        },
      },
      right: {
        position: "right",
        attrs: {
          circle: {
            r: 4,
            magnet: true,
            stroke: "#5F95FF",
            strokeWidth: 1,
            fill: "#fff",
            style: {
              visibility: "hidden",
            },
          },
        },
      },
      bottom: {
        position: "bottom",
        attrs: {
          circle: {
            r: 4,
            magnet: true,
            stroke: "#5F95FF",
            strokeWidth: 1,
            fill: "#fff",
            style: {
              visibility: "hidden",
            },
          },
        },
      },
      left: {
        position: "left",
        attrs: {
          circle: {
            r: 4,
            magnet: true,
            stroke: "#5F95FF",
            strokeWidth: 1,
            fill: "#fff",
            style: {
              visibility: "hidden",
            },
          },
        },
      },
    },
    items: [
      {
        group: "top",
      },
      {
        group: "right",
      },
      {
        group: "bottom",
      },
      {
        group: "left",
      },
    ],
  }

  let blockele: Array<object> = []
  Object.values(props.flowData.statusList).forEach((v: any) => {
    blockele.push(
      graphObj.graph.createNode(
        {
          uuid: `uuid-${v.id}`,
          shape: "rect",
          width: 53,
          height: 20,
          label: v.label,
          attrs: {
            body: {
              rx: 20,
              ry: 26,
              fill: v.background,
              strokeWidth: 1,
              stroke: "#ccc",
            },
            text: {
              fontSize: 12,
              fill: "#fff",
            },
          },
          ports: { ...ports },
          data: {
            ...v,
          },
        },
        true,
      ),
    )
  })
  graphObj.stencil.load([...blockele], "baseflow")
  graphObj.spinning = false
}

/**
 * 事件
 */
const initEvent = (): void => {
  // 控制连接桩显示/隐藏
  const showPorts = (ports, show) => {
    for (let i = 0, len = ports.length; i < len; i = i + 1) ports[i].style.visibility = show ? "visible" : "hidden"
  }
  graphObj.graph.on("node:mouseenter", () => {
    const container = document.getElementById("graph-container")
    const ports = container.querySelectorAll(".x6-port-body")
    showPorts(ports, true)
  })
  graphObj.graph.on("node:mouseleave", () => {
    const container = document.getElementById("graph-container")
    const ports = container.querySelectorAll(".x6-port-body")
    showPorts(ports, false)
  })

  // 单击某个节点触发
  graphObj.graph.on("node:click", ({ e, x, y, node, view }) => {
    tempCurNode = node
    graphObj.currentNode = node
  })

  // 单击画布空白区域，隐藏样式面板
  graphObj.graph.on("blank:click", ({ e, x, y, node, view }) => {
    graphObj.currentNode = node
  })
}

const onSave = (data: object): void => {
  emits("onSaveFn", data)
}

// 单击样式面板则爹图标，进行则爹和展示
const setPanel = (flag: boolean): void => {
  graphObj.isShowPanel = flag
  console.log(111)

  if (flag) {
    nextTick(() => {
      graphObj.currentNode = tempCurNode
    })
  } else {
    nextTick(() => {
      graphObj.currentNode = {}
    })
  }
}
</script>

<style scoped lang="less">
.workflow-view {
  max-height: 100vh;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  .tabbar-view {
    display: flex;
    align-items: center;
    flex-basis: 55px;
    min-height: 55px;
    background-color: #fff;
    box-shadow: 0 2px 8px 0 rgba(0, 0, 0, 0.1);
  }
  .workflow-container {
    flex: 1;
    position: relative;
    display: flex;
    justify-content: space-between;
    .stencil-view {
      flex-basis: 260px;
      width: 260px;
      height: calc(100vh - 55px);
      position: relative;
      border-right: 1px solid #dfe3e8;
      :deep(.x6-widget-stencil-content) {
        &::-webkit-scrollbar {
          width: 6px;
          height: 10px;
        }
        &::-webkit-scrollbar-thumb {
          background-color: #ddd;
          border-radius: 3px;
        }
      }
    }
    .graph-view {
      flex: 1;
    }
    .panel-icon {
      position: relative;
      left: 6px;
      z-index: 100;
      font-size: 18px;
      margin-top: 300px;
      color: #aaa;
    }
    // .slideLeft {
    //   transition: 0.6s ease-in;
    //   margin-right: 0;
    // }

    // .slideRight {
    //   transition: 0.6s ease-in;
    //   margin-right: -260px;
    // }
  }
}

.x6-widget-stencil {
  background-color: #fff;
}

.x6-widget-stencil-title {
  background-color: #fff;
  text-align: left !important;
}

.x6-widget-stencil-group-title {
  background-color: #fff !important;
}

.x6-widget-transform {
  margin: -1px 0 0 -1px;
  padding: 0px;
  border: 1px solid #239edd;
}

.x6-widget-transform > div {
  border: 1px solid #239edd;
}

.x6-widget-transform > div:hover {
  background-color: #3dafe4;
}

.x6-widget-transform-active-handle {
  background-color: #3dafe4;
}

.x6-widget-transform-resize {
  border-radius: 0;
}

.x6-widget-selection-inner {
  border: 1px solid #239edd;
}

.x6-widget-selection-box {
  opacity: 0;
}
</style>
